package com.zhongan.gateway.filter;

import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.zhongan.gateway.bean.Api;
import com.zhongan.gateway.bean.Developer;
import com.zhongan.gateway.bean.DeveloperIp;
import com.zhongan.gateway.common.constant.GwDeveloperApiConstant;
import com.zhongan.gateway.common.enums.GatewayErrorCodeEnum;
import com.zhongan.gateway.common.exception.GatewayException;
import com.zhongan.gateway.common.utils.EmptyCheckUtil;
import com.zhongan.gateway.common.utils.HttpServletUtil;
import com.zhongan.gateway.dto.RequestBase;
import com.zhongan.gateway.service.ApiService;
import com.zhongan.gateway.service.DeveloperService;
import com.zhongan.gateway.service.SecurityService;

@Component
public class SystemCheckZuulFilter extends ZuulFilter {
    private Logger log = LoggerFactory.getLogger(SystemCheckZuulFilter.class);

    @Resource
    private DeveloperService developerService;

    @Resource
    private SecurityService  securityService;

    @Resource
    private ApiService       apiService;

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String uri = request.getRequestURI();
        if (uri != null && uri.startsWith(GwDeveloperApiConstant.COMMON_GROOVY_URL)) {
            return false;
        }
        return true;
    }

    @Override
    public Object run() {
        log.info("进入检查参数filter");
        //取出httpServletRequest
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest httpServletRequest = ctx.getRequest();
        try {

            //取出requestBodyStr
            String requestBodyStr = HttpServletUtil.getRequestBodyStr(httpServletRequest);

            RequestBase requestBase = JSONObject.parseObject(requestBodyStr, RequestBase.class, Feature.OrderedField);

            EmptyCheckUtil.check(requestBase, "appKey", "bizContent", "signValue", "timestamp");

            String appKey = requestBase.getAppKey();

            String serviceName = requestBase.getServiceName();
            if (StringUtils.isEmpty(serviceName)) {
                //参数中不传serviceName，开发者调用网关的url是restful样式
                serviceName = httpServletRequest.getRequestURI().replace(GwDeveloperApiConstant.COMMON_URL, "");

            }
            log.info("serviceName={},appKey={}", serviceName, requestBase.getAppKey());

            Developer developer = developerService.selectDeveloperByAppKey(appKey);
            if (developer == null) {
                throw new GatewayException(GatewayErrorCodeEnum.UNKNOW_APPKEY_ERROR.getCode(), "该appkey不合法,appkey="
                        + appKey);
            }

            Api api = apiService.selectApi(serviceName, requestBase.getVersion());
            if (api == null) {
                throw new GatewayException(GatewayErrorCodeEnum.UNKNOW_METHOD_ERROR.getCode(), "该api不存在,serviceName="
                        + serviceName + " ,version=" + requestBase.getVersion());

            }
            httpServletRequest.setAttribute("api", api);
            httpServletRequest.setAttribute("requestBase", requestBase);
            httpServletRequest.setAttribute("developer", developer);

            //ip白名单校验
            ipCheck(developer.getId(), httpServletRequest);

            //验签解密
            String publicKey = developer.getPublicKey();
            JSONObject biz = securityService.checkSignAndDecrypt(requestBase, publicKey, developer.getEncryptType());
            requestBase.setBizContent(biz);
            requestBase.setServiceName(serviceName);
        } catch (GatewayException ge) {
            httpServletRequest.setAttribute("gatewayException", ge);
            throw new RuntimeException();
        } catch (Exception e) {
            log.error("权限校验出现异常" + e.getMessage(), e);
            httpServletRequest.setAttribute(
                    "gatewayException",
                    new GatewayException(GatewayErrorCodeEnum.UN_KNOWN.getCode(), GatewayErrorCodeEnum.UN_KNOWN
                            .getMsg()));
            throw new RuntimeException();
        }
        return null;
    }

    /**
     * ip白名单
     * 
     * @param devId
     * @param request
     * @throws GatewayException
     */
    private void ipCheck(Long devId, HttpServletRequest request) throws GatewayException {
        String ip = getIRealIPAddr(request);
        log.info("访问ip为：" + ip);
        List<DeveloperIp> list = developerService.selectIps(devId);
        if (null != list && !list.isEmpty()) {
            for (DeveloperIp di : list) {
                if (ip.equals(di.getIp())) {
                    return;
                }
            }
            throw new GatewayException(GatewayErrorCodeEnum.ILLEGAL_IP.getCode(), "ip未加入白名单," + ip);

        }
    }

    /**
     * 获取真实ip地址
     * 
     * @param request
     * @return
     */
    private String getIRealIPAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "null".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "null".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "null".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
